package com.game.modular.game.playerAssets.service;

import com.game.comment.exection.ServiceException;
import com.game.modular.game.playerAssets.domain.PlayerBag;
import com.game.modular.game.playerAssets.mapper.PlayerBagMapper;
import com.game.modular.game.playerAssets.service.base.PlayerBagBaseServiceImpl;
import com.game.modular.gameCore.cultivate.domain.CoreAccountConfig;
import com.game.modular.gameCore.cultivate.domain.CoreProp;
import com.game.modular.gameCore.cultivate.service.impl.CoreAccountConfigServiceImpl;
import com.game.modular.gameCore.cultivate.service.impl.CorePropServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 背包物品(PlayerBag)表服务实现类
 *
 * @author cxy
 * @since 2024-07-26 17:49:04
 */
@Slf4j
@Service
public class PlayerBagServiceImpl extends PlayerBagBaseServiceImpl {
    @Resource
    private PlayerBagMapper playerBagMapper;
    @Resource
    private CorePropServiceImpl corePropServiceImpl;
    @Resource
    private CoreAccountConfigServiceImpl coreAccountConfigServiceImpl;
    @Qualifier("playerBagBaseServiceImpl")
    @Resource
    private PlayerBagBaseServiceImpl playerBagBaseServiceImpl;

    // 注册init
    @Transactional
    public void registerInit(Long playerId) {
        CoreAccountConfig coreAccountConfig = coreAccountConfigServiceImpl.getCache(1L);
        Map<Long, Long> propInfo = coreAccountConfig.getPropInfo();
        propInfo.forEach((corePropId, num) -> obtainBackpackItems(playerId, num, corePropId));
    }

    public void obtainBackpackItems(Long playerId, Long quantity, Long corePropId) {
        CoreProp coreProp = corePropServiceImpl.getCache(corePropId);
        Long stack = coreProp.getStack();

        if (stack == 0) {
            handleZeroStack(playerId, quantity, corePropId);
        }
        if (stack == 1) {
            handleOneStack(coreProp, playerId, quantity);
        }
        if (stack > 1) {
            handlePositiveStack(coreProp, playerId, quantity, corePropId);
        }
    }

    /**
     * 处理堆叠等于0 的背包物品
     *
     * @param playerId
     * @param quantity
     * @param corePropId
     */
    private void handleZeroStack(Long playerId, Long quantity, Long corePropId) {
        List<PlayerBag> playerBags = eqlist(PlayerBag.builder()
                .uid(playerId)
                .corePropId(corePropId)
                .build()
        );
        PlayerBag targetBag;

        if (!playerBags.isEmpty()) {
            targetBag = playerBags.remove(0);
            long targetNum = targetBag.getNum() + quantity;
            if (targetNum < 0) {
                throw new IllegalArgumentException("数量不足");
            }
            targetBag.setNum(targetNum);
            updateById(targetBag);
        } else {
            targetBag = PlayerBag.builder().build();
            targetBag.setUid(playerId);
            targetBag.setNum(quantity);
            targetBag.setCorePropId(corePropId);
            targetBag.setStatus(1);
            targetBag.setGetTime(new Date());
            save(targetBag);
        }
    }

    /**
     * 处理堆叠为1 的背包物品
     *
     * @param coreProp
     * @param playerId
     * @param quantity
     */
    private void handleOneStack(CoreProp coreProp, Long playerId, Long quantity) {
        if (quantity < 1) {
            throw new ServiceException("不支持的操作");
        }
        for (long l = 0L; l < quantity; l++) {
            PlayerBag build = PlayerBag.builder()
                    .uid(playerId)
                    .num(1L)
                    .corePropId(coreProp.getId())
                    .status(1)
                    .getTime(new Date())
                    .build();
            save(build);
        }
    }

    /**
     * 处理堆叠大于1 的背包物品
     *
     * @param coreProp
     * @param playerId
     * @param quantity
     * @param corePropId
     */
    private void handlePositiveStack(
            CoreProp coreProp,
            Long playerId,
            @NotNull(message = "增加/减少的数量不能为空") Long quantity,
            Long corePropId
    ) {
        Long stack = coreProp.getStack();
        List<PlayerBag> playerBags = eqlist(PlayerBag.builder()
                .uid(playerId)
                .corePropId(corePropId)
                .build()
        );

        long havingQuantity = playerBags.stream().mapToLong(PlayerBag::getNum).sum();
        long targetHavingQuantity = havingQuantity + quantity;


        if (targetHavingQuantity < 0) {
            throw new IllegalArgumentException("数量不足");
        }
        if (quantity + stack < 0) {
            throw new IllegalArgumentException("一次性使用数量不能超过" + stack);
        }

        while (quantity != 0) {
            PlayerBag targetBag = PlayerBag.builder().build();
            targetBag.setUid(playerId);
            targetBag.setCorePropId(corePropId);
            targetBag.setStatus(1);
            targetBag.setGetTime(new Date());
            if (quantity <= stack) {// 单元足够
                targetBag.setNum(quantity);
                save(targetBag);
                quantity -= quantity;
            } else {// 单元不够
                targetBag.setNum(stack);
                save(targetBag);
                quantity -= stack;
            }
        }
        organizeBackpacks(playerId, corePropId);
    }

    private void organizeBackpacks(Long playerId, Long corePropId) {
        CoreProp coreProp = corePropServiceImpl.getCache(corePropId);
        Long stack = coreProp.getStack();
        List<PlayerBag> playerBags =
                eqlist(PlayerBag.builder()
                        .uid(playerId)
                        .corePropId(corePropId).build())
                        .stream().filter(item -> !Objects.equals(item.getNum(), stack))
                        .sorted(Comparator.comparing(PlayerBag::getId)).collect(Collectors.toList());
        long sum = playerBags.stream().mapToLong(PlayerBag::getNum).sum();
        for (PlayerBag playerBag : playerBags) {
            removeById(playerBag);
        }

        while (sum != 0) {
            PlayerBag targetBag = PlayerBag.builder().build();
            targetBag.setUid(playerId);
            targetBag.setCorePropId(corePropId);
            targetBag.setStatus(1);
            targetBag.setGetTime(new Date());
            if (sum >= stack) {
                sum -= stack;
                targetBag.setNum(stack);
                save(targetBag);
            }
            if (sum < stack) {
                targetBag.setNum(sum);
                save(targetBag);
                break;
            }
        }
        eqlist(PlayerBag.builder()
                .uid(playerId)
                .corePropId(corePropId)
                .build()
        );
    }

    public PlayerBag use(
            @Valid @NotNull(message = "玩家uid不能为空") Long playerId,
            @Valid @NotNull(message = "道具id不能为空") Long coreId,
            @Valid @NotNull(message = "使用数量不能为空") @Min(value = 1, message = "使用数量不能为空1") Long num
    ) {
        CoreProp coreProp = corePropServiceImpl.getCache(coreId);
        PlayerBag playerBag = eqSelect(PlayerBag.builder().uid(playerId).corePropId(coreId).build());

        return option(num, coreProp, playerBag);
    }

    public PlayerBag useBagItem(
            @Valid @NotNull(message = "玩家uid不能为空") Long playerId,
            @Valid @NotNull(message = "物品id不能为空") Long playerBagId,
            @Valid @NotNull(message = "使用数量不能为空") @Min(value = 1, message = "使用数量不能为空1") Long num,
            Long playerHeroId
    ) {
        PlayerBag playerBag = eqSelect(PlayerBag.builder()
                .uid(playerId)
                .id(playerBagId)
                .build()
        );
        if (playerBag == null) {// 判断道具是否存在
            throw new ServiceException("道具不存在" + playerBagId + ":" + playerBag);
        }
        CoreProp coreProp = corePropServiceImpl.getCache(playerBag.getCorePropId());
        playerBag.setPlayerHeroId(playerHeroId);
        return option(num, coreProp, playerBag);
    }

    @Transactional
    public void modifyUnlimitedStackingQuantity(
            @Valid @NotNull(message = "背包物品不能为空") PlayerBag select,
            @Valid @NotNull(message = "使用数量不能为空") Long num
    ) {
        PlayerBag playerBag = playerBagBaseServiceImpl.eqSelect(select);
        if (playerBag == null){
            log.info("modifyUnlimitedStackingQuantity:道具不存在");
            return;
        }
        Long stack = playerBag.getStack();
        if (stack == 0) {
            playerBag.setNum(num);
            updateById(playerBag);
        }
        if (stack == 1) {
            throw new ServiceException("该道具无法设置堆叠数量");
        }
        if (stack > 1) {
            long res = playerBag.getNum() + num;
            if (res < 0) {
                throw new ServiceException("数量不足");
            }
            if (res > stack) {
                long newNum = res - stack;
            }
        }

    }

    public PlayerBag backBagItem(
            @Valid @NotNull(message = "玩家uid不能为空") Long playerId,
            @Valid @NotNull(message = "物品id不能为空") Long playerBagId,
            @Valid @NotNull(message = "使用数量不能为空") @Min(value = 1, message = "使用数量不能为空1") Long num
    ) {
        PlayerBag playerBag = eqSelect(PlayerBag.builder()
                .uid(playerId)
                .id(playerBagId)
                .build()
        );
        if (playerBag == null) {// 判断道具是否存在
            throw new ServiceException("道具不存在" + playerBagId + ":" + playerBag);
        }
        CoreProp coreProp = corePropServiceImpl.getCache(playerBag.getCorePropId());
        playerBag.setCoreProp(coreProp);

        return backOption(num, coreProp, playerBag);
    }

    private PlayerBag option(Long num, CoreProp coreProp, PlayerBag playerBag) {
        Integer type = coreProp.getType();
        Integer status = playerBag.getStatus();
        switch (type) {
            case 1:// 货币
                playerBag.setNum(playerBag.getNum() - num);
                updateById(playerBag);
                break;
            case 2:// 道具
                playerBag.setNum(playerBag.getNum() - num);
                updateById(playerBag);
                break;
            case 3:// 礼包
                playerBag.setNum(playerBag.getNum() - num);
                updateById(playerBag);
                break;
            case 4:// 装备
                if (status == 2) {
                    throw new ServiceException("装备使用中");
                }
                if (status == 1) {
                    playerBag.setStatus(2);
                    updateById(playerBag);
                    playerBag.setCoreProp(coreProp);
                }
                break;
            case 5:// 坐骑
                if (status == 2) {
                    throw new ServiceException("装备使用中");
                }
                if (status == 1) {
                    playerBag.setStatus(2);
                    updateById(playerBag);
                    playerBag.setCoreProp(coreProp);
                }
                break;
            case 6:// 武将信物
                playerBag.setNum(playerBag.getNum() - num);
                updateById(playerBag);
                break;
            case 7:// 技能信物
                playerBag.setNum(playerBag.getNum() - num);
                updateById(playerBag);
                break;
        }
        // 获取使用的结果
        return playerBag;
    }

    private PlayerBag backOption(Long num, CoreProp coreProp, PlayerBag playerBag) {
        Integer type = coreProp.getType();
        Integer status = playerBag.getStatus();
        switch (type) {
            case 1:// 货币
                playerBag.setNum(playerBag.getNum() + num);
                updateById(playerBag);
                break;
            case 2:// 道具
                playerBag.setNum(playerBag.getNum() + num);
                updateById(playerBag);
                break;
            case 3:// 礼包
                playerBag.setNum(playerBag.getNum() + num);
                updateById(playerBag);
                break;
            case 4:// 装备
                if (status == 1) {
                    throw new ServiceException("装备未使用");
                }
                if (status == 2) {
                    playerBag.setStatus(1);
                    updateById(playerBag);
                    playerBag.setCoreProp(coreProp);
                }
                break;
            case 5:// 坐骑
                if (status == 1) {
                    throw new ServiceException("坐骑未使用");
                }
                if (status == 2) {
                    playerBag.setStatus(1);
                    updateById(playerBag);
                    playerBag.setCoreProp(coreProp);
                }
                break;
            case 6:// 武将信物
                playerBag.setNum(playerBag.getNum() + num);
                updateById(playerBag);
                break;
            case 7:// 技能信物
                playerBag.setNum(playerBag.getNum() + num);
                updateById(playerBag);
                break;
        }
        // 获取使用的结果
        return playerBag;
    }


    /**
     * 重置 pvp背包
     *
     */
    @Transactional
    public void resetPvp(Long playerId) {
        modifyUnlimitedStackingQuantity(PlayerBag.builder().uid(playerId).corePropId(4L).build(),0L);
        modifyUnlimitedStackingQuantity(PlayerBag.builder().uid(playerId).corePropId(5L).build(),0L);
    }
}
